<?php


namespace app\queue\stomp;


use app\queue\BaseConsumer;
use common\model\OrderTaskFileListModel;
use common\model\OrderTaskListModel;
use common\model\OrderTaskUpstreamVersionModel;
use common\model\ProjectModel;
use common\model\TaskModel;
use common\model\VersionModel;
use common\service\CommonService;
use common\service\OrderService;
use common\service\ReviewRequestService;
use common\service\StatusService;
use common\service\TaskRepairOrderService;
use think\Exception;
use think\module\Module;
use Throwable;
use Webman\Stomp\Client;
use Webman\Stomp\RetryAbleConsumer;

/**
 * 版本发布异步事件
 */
class VersionPublishedConsumer extends BaseConsumer implements RetryAbleConsumer
{
    // 要消费的队列名
    public $queue = 'version_published';

    // 连接名，对应 config/redis_queue.php 里的连接`
    public $connection = 'default';

    /**
     * 消费
     * @param $data
     * @return void
     */
    public function doConsume($data)
    {
        $v = model(VersionModel::class)->forceMasterDB()->find($data['id']);
        if (empty($v)) {
            return;
        }
        try {
            model(VersionModel::class)->modifyItem(['id' => $v['id'], 'published' => time()]);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            $this->recordPublishedVersionIdInTaskJson($v);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            TaskRepairOrderService::getInstance()->dealFinishRepairOrderAffectedTask([$v['link_id']]);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            $this->changeTaskStatusToDone($v);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            // 任务发布新版本  订单检查是否有需要生成上传记录的
            Client::send('version_order_task_upstream_check', build_queue_data_with_xu(['version_id' => $v['id']]));
            if (false) {
                // 记录异常通知
                $queueData = [
                    'module_code' => 'version',
                    'type' => 'version_publish',
                    'info' => '',
                    'data' => $v,
                ];
                Client::send("abnormal_info_store", build_queue_data_with_xu($queueData));
            }

        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            // 外包版本发布 添加甲方任务回收记录
            $this->outsideVersionPublishOrderTaskUpstreamCheck($v);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }

    /**
     * 重试间隔
     * @return int
     */
    public function getTtr()
    {
        return 20;
    }

    /**
     * 能否重试
     * @param $attempt
     * @param $error
     * @return bool
     */
    public function canRetry($attempt, $error)
    {
        trace(format_exception_info($error), 'ERR');
        return $attempt <= 3;
    }

    /**
     * 记录最新的已发布版本id
     * @param $v
     * @return void
     */
    private function recordPublishedVersionIdInTaskJson($v)
    {
        model(TaskModel::class)
            ->execute("UPDATE task SET 
                json = JSON_SET(IFNULL(json,'{}'), '$.task_latest_published_version_id', 
                    {$v['id']}), 
                delivery_time = " . time() . " 
                WHERE id = {$v['link_id']}");
    }

    /**
     * 修改任务到已完成 关闭其他未结束的审核
     * @param $v
     * @return void
     * @throws Exception
     * @throws \Exception
     */
    private function changeTaskStatusToDone($v)
    {
        $taskCommonService = CommonService::instance('task');
        $versionModuleId = module_by_code('version')['id'];
        $reviewRequestList = model(VersionModel::class)
            ->join("review_request on review_request.module_id = {$versionModuleId} and review_request.link_id = version.id")
            ->where([
                'version.module_id' => $v['module_id'],
                'version.link_id' => $v['link_id'],
                'review_request.is_reviewed' => 'no',
            ])
            ->field('review_request.*')
            ->select();

        foreach ($reviewRequestList as $reviewRequest) {
            ReviewRequestService::getInstance()->closeReviewRequest($reviewRequest);
        }
        $doneStatus = StatusService::getInstance()->getTaskDoneStatus();
        $taskCommonService->update(['id' => $v['link_id'], 'task_status' => $doneStatus['id']], 'task', false);
    }


    /**
     * 添加订单任务版本传输记录
     * @param $task
     * @param $sourceTask
     * @return void
     * @throws \Exception
     */
    private function addOrderTaskUpstreamVersionData($task, $sourceTask)
    {
        $taskModule = Module::$moduleDictData['module_index_by_code']['task'];
        $latestDoneVersion = model(VersionModel::class)->forceMasterDB()
            ->where(['link_id' => $task['id'], 'module_id' => $taskModule['id']])
            ->where(['is_pass' => 'yes', 'is_publish' => 'yes'])
            ->order("id desc")
            ->find();

        if (empty($latestDoneVersion)) {
            return;
        }
        $orderTaskUpstreamVersionData = [
            'from_tenant_id' => $task['tenant_id'],
            'to_tenant_id' => $sourceTask['tenant_id'],
            'from_project_id' => $task['project_id'],
            'to_project_id' => $sourceTask['project_id'],
            'entity_id' => $task['entity_id'],
            'task_id' => $task['id'],
            'version_id' => $latestDoneVersion['id'],
            'created' => time(),
            'created_by' => $task['executor'],
        ];
        // 一个任务一个版本 只会提交给甲方一次
        $orderTaskUpstreamVersionDataExistFilter = [
            'to_tenant_id' => $sourceTask['tenant_id'],
            'task_id' => $task['id'],
            'version_id' => $latestDoneVersion['id'],
        ];
        $orderTaskUpstreamVersionDataExist = model(OrderTaskUpstreamVersionModel::class)
            ->forceMasterDB()
            ->where($orderTaskUpstreamVersionDataExistFilter)
            ->field('id')
            ->find();
        // 添加甲方接受版本记录
        if (!empty($orderTaskUpstreamVersionDataExist)) {
            return;
        }
        APP_DEBUG && trace('partyB ADD order_task_upstream_version transfer record', "DEBUG");
        model(OrderTaskUpstreamVersionModel::class)->add($orderTaskUpstreamVersionData);
    }

    /**
     * 添加订单任务文件传输列表
     * @param $order
     * @param $task
     * @param $sourceTask
     * @return void
     * @throws \Exception
     */
    private function addOrderTaskFileListData($order, $task, $sourceTask)
    {
        $orderTaskFileListFilter = [
            'order_id' => $order['id'],
            'from_project_id' => $task['project_id'],
            'to_project_id' => $sourceTask['project_id'],
            'task_id' => $task['id'],
        ];
        $orderTaskFileList = model(OrderTaskFileListModel::class)->forceMasterDB()->where($orderTaskFileListFilter)->find();
        // 传输给甲方的记录,只会建立一次
        if (!empty($orderTaskFileList)) {
            return;
        }
        $orderTaskFileItem = [
            'from_tenant_id' => $task['tenant_id'],
            'to_tenant_id' => $sourceTask['tenant_id'],
            'order_id' => $order['id'],
            'from_project_id' => $task['project_id'],
            'to_project_id' => $sourceTask['project_id'],
            'task_id' => $task['id'],
            'entity_id' => $task['entity_id'],
            'step_id' => $task['step_id'],
            'step_category_id' => $task['step_category_id'],
            'created' => time(),
            'downstream_task_id' => $sourceTask['id'],
            'created_by' => $task['executor'],
        ];
        APP_DEBUG && trace('partyB ADD order_task_file_list because task status is changed to done status', 'DEBUG');
        model(OrderTaskFileListModel::class)->add($orderTaskFileItem);
    }

    /**
     * 外包版本发布 添加甲方任务回收记录
     * @param $version
     * @return void
     */
    private function outsideVersionPublishOrderTaskUpstreamCheck($version)
    {
        $task = model(TaskModel::class)->find($version['link_id']);
        $project = model(ProjectModel::class)->find($task['project_id']);
        if ($project['type'] != 'outsource') {
            return;
        }
        $orderTaskListItem = OrderService::getInstance()->getOrderTaskListItemByRealTaskId($task['id'], ['status' => OrderTaskListModel::STATUS_DEFAULT]);
        if (empty($orderTaskListItem)) {
            return;
        }
        $sourceTask = model(TaskModel::class)->forceMasterDB()->find($orderTaskListItem['task_id']);
        if (empty($sourceTask)) {
            return;
        }
        $order = OrderService::getInstance()->getOrderByStepTaskId($task['id']);
        if (empty($order)) {
            return;
        }
        try {
            $this->addOrderTaskUpstreamVersionData($task, $sourceTask);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
        try {
            $this->addOrderTaskFileListData($order, $task, $sourceTask);
        } catch (Throwable $e) {
            trace(format_exception_info($e), 'ERR');
        }
    }
}
